package com.nd.sdp.android.configuration;

import android.content.Context;
import android.util.Log;

import com.nd.sdp.android.configuration.exception.ConfigurationFetchException;
import com.nd.sdp.android.configuration.internal.IServicePool;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * AnnotationConfigurations
 * Created by Young on 2018/4/25.
 */
@SuppressWarnings("unchecked")
public class AnnotationConfigurations implements Configurations {

    private static final String TAG = "Configurations";

    private IServicePool mBeanHolder;

    private Context mContext;

    public AnnotationConfigurations(Context context) {
        mContext = context;
        try {
            mBeanHolder = (IServicePool) Class.forName("com.nd.sdp.android.configuration.internal.BeanHolder")
                    .newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if (mBeanHolder == null) {
            throw new IllegalStateException("Init Error,Check AnnotationProcessor Setting");
        }
    }

    @Override
    public <T> T getBean(Class<T> tClass) {
        Map<Class, List<Class>> beanConfiguration = mBeanHolder.getBeanConfiguration();
        List<Class> classList = beanConfiguration.get(tClass);
        if (classList == null) {
            return null;
        }
        if (classList.size() == 1) {
            Class<T> aClass = classList.get(0);
            return newInstance(aClass);
        } else {
            StringBuilder classNameString = new StringBuilder();
            for (Class allClass : classList) {
                classNameString.append(allClass.getName())
                        .append("\n");
            }
            Log.e(TAG, "All Configuration:" + classNameString.toString());
            throw new ConfigurationFetchException("This configuration interface has multiple implementation");
        }
    }

    private <T> T newInstance(Class<T> aClass) {
        try {
            return aClass.newInstance();
        } catch (Exception e) {
            try {
                Constructor<T> constructorWithContext = aClass.getConstructor(Context.class);
                if (constructorWithContext != null) {
                    return constructorWithContext.newInstance(mContext);
                }
            } catch (Exception ignored) {
            }
        }
        throw new ConfigurationFetchException("Cannot new Instance " + aClass.getName() + " because no constructor matched");
    }

    @Override
    public <T> List<T> getBeans(Class<T> tClass) {
        Map<Class, List<Class>> beanConfiguration = mBeanHolder.getBeanConfiguration();
        List<Class> classList = beanConfiguration.get(tClass);
        if (classList == null) {
            return null;
        }
        if (classList.size() == 1) {
            Log.e(TAG, "Configuration:" + classList.get(0).getName());
            throw new ConfigurationFetchException("This configuration interface has only one implementation");
        }
        List<T> instances = new ArrayList<>();
        for (Class c : classList) {
            Class<T> beanClass = (Class<T>) c;
            T instance = newInstance(beanClass);
            instances.add(instance);
        }
        return instances;
    }

}
